package model.core;

import java.util.ArrayList;
import java.util.StringTokenizer;
import model.ability.*;
import model.area_effect.MapAreaOfEffect;
import model.area_effect.Trap;
import model.entity.*;
import model.item.*;
import model.effects.*;
import model.map.GameMap;
import model.map.MapPoint;
import model.stats.StatsPersistMods;
import model.stats.StatsTempMods;

/**
 * 
 * @author Paul
 *
 */

public class GameInstantiation {
	private LineParser lineParser = new LineParser();
	
	public GameInstantiation(){
		
	}
	
	/*
	 * "name;val"
	 */
	public void createSkill(String id){
		ArrayList<String> tokens = lineParser.parseStringOnSemicolon(id);
		String name = tokens.get(0);
		int val = Integer.parseInt(tokens.get(1));
		SkillsLibrary.getInstance().put(name, new PassiveSkill(name, val));
	}
	
	//"type;..."
	public void createEffect(String id){
		ArrayList<String> tokens = lineParser.parseStringOnSemicolon(id);
		String type = tokens.remove(0);
		
		if (type.equals("Kill")){
			createKillEffect(tokens);
		}
		else if (type.equals("PushEntity")){
			createPushEffect(tokens);
		}
		else if (type.equals("Teleport")){
			createTeleportEffect(tokens);
		}
		else if (type.equals("Experience")){
			createXPEffect(tokens);
		}
		else if (type.equals("StatMod")){
			createStatModEffect(tokens);
		}
		else if (type.equals("Sleep")){
			createSleepEffect(tokens);
		}
		else if (type.equals("Heal")){
			createHealEffect(tokens);
		}
		else if (type.equals("Enchant")){
			createEnchantEffect(tokens);
		}
		else if (type.equals("Harm")){
			createHarmEffect(tokens);
		}
	}
	
	public void createKillEffect(ArrayList<String> tokens){
		String name = tokens.get(0);
		int livesLost = Integer.parseInt(tokens.get(1));
		EffectsLibrary.getInstance().put(name, new Kill(livesLost));
	}
	public void createPushEffect(ArrayList<String> tokens){
		String name = tokens.get(0);
		int intensity = Integer.parseInt(tokens.get(1));
		EffectsLibrary.getInstance().put(name, new PushEntity(intensity));
	}
	//"name;baseVal;(x,y)"
	public void createTeleportEffect(ArrayList<String> tokens){
		String name = tokens.get(0);
		int baseVal = Integer.parseInt(tokens.remove(1));
		ArrayList<String> t2 = lineParser.parseStringOnCommaAndRemoveParen(tokens.get(2));
		MapPoint p = new MapPoint(Integer.parseInt(t2.get(0)), Integer.parseInt(t2.get(1)));
		EffectsLibrary.getInstance().put(name, new Teleport(baseVal, p));
	}
	public void createXPEffect(ArrayList<String> tokens){
		String name = tokens.get(0);
		int xpMod = Integer.parseInt(tokens.get(1));
		EffectsLibrary.getInstance().put(name, new Experience(xpMod));
	}
	//"name;baseVal;(modType,val,dur);(modType,val,dur);..."
	public void createStatModEffect(ArrayList<String> tokens){
		String name = tokens.remove(0);
		int baseVal = Integer.parseInt(tokens.remove(1));
		StatsTempMods mods = new StatsTempMods();
		for (String s : tokens){
			ArrayList<String> mod = lineParser.parseStringOnCommaAndRemoveParen(s);
			addTempModifier(mod, mods);
		}
		EffectsLibrary.getInstance().put(name, new StatMod(baseVal, mods));
	}
	public void createSleepEffect(ArrayList<String> tokens){
		String name = tokens.get(0);
		int duration = Integer.parseInt(tokens.get(1));
		EffectsLibrary.getInstance().put(name, new SleepEffect(duration));
	}
	public void createHealEffect(ArrayList<String> tokens){
		String name = tokens.get(0);
		int health = Integer.parseInt(tokens.get(1));
		EffectsLibrary.getInstance().put(name, new Heal(health));
	}
	public void createEnchantEffect(ArrayList<String> tokens){
		String name = tokens.get(0);
		int enchantMod = Integer.parseInt(tokens.get(1));
		EffectsLibrary.getInstance().put(name, new EnchantEffect(enchantMod));
	}
	public void createHarmEffect(ArrayList<String> tokens){
		String name = tokens.get(0);
		int damage = Integer.parseInt(tokens.get(1));
		EffectsLibrary.getInstance().put(name, new Harm(damage));
	}
	
	
	/*
	 * "type;name;occupation;(int,int)[location];(int,int)[direction];legsName;AIBehaviorName"
	 */
	public void createNPC(String id){
		ArrayList<String> tokens = lineParser.parseStringOnSemicolon(id);
		String type = tokens.remove(0);
		if (type.equals("Pet")){
			createPet(tokens);
		}
		else if (type.equals("Merchant")){
			createMerchant(tokens);
		}
		else if (type.equals("Mount")){
			createMount(tokens);
		}
	}
	
	public void createPet(ArrayList<String> tokens){
		String name = tokens.get(0);
		String occupation = tokens.get(1);
		ArrayList<String> t2 = lineParser.parseStringOnCommaAndRemoveParen(tokens.get(2));
		MapPoint loc = new MapPoint(Integer.parseInt(t2.get(0)),Integer.parseInt(t2.get(1)));
		t2 = lineParser.parseStringOnCommaAndRemoveParen(tokens.get(3));
		MapPoint dir = new MapPoint(Integer.parseInt(t2.get(0)),Integer.parseInt(t2.get(1)));
		String legsName = tokens.get(4);
		String AIName = tokens.get(4);
		AIBehavior behavior = null;
		if (AIName.equals("StandStill")){
			behavior = new StandStill();
		}
		else if (AIName.equals("Follow")){
			//behavior = new Follow(4);
		}
		else if (AIName.equals("Wander")){
			behavior = new Wander(20, 10);
		} 
		else if (AIName.equals("Attack")){
			//behavior = new Attack();
		}
		EntityLibrary.getInstance().put(name, new Pet());
	}
	
	public void createMerchant(ArrayList<String> tokens){
		String name = tokens.get(0);
		String occupation = tokens.get(1);
		ArrayList<String> t2 = lineParser.parseStringOnCommaAndRemoveParen(tokens.get(2));
		MapPoint loc = new MapPoint(Integer.parseInt(t2.get(0)),Integer.parseInt(t2.get(1)));
		t2 = lineParser.parseStringOnCommaAndRemoveParen(tokens.get(3));
		MapPoint dir = new MapPoint(Integer.parseInt(t2.get(0)),Integer.parseInt(t2.get(1)));
		String legsName = tokens.get(4);
		String AIName = tokens.get(4);
		AIBehavior behavior = null;
		if (AIName.equals("StandStill")){
			behavior = new StandStill();
		}
		else if (AIName.equals("Follow")){
			//behavior = new Follow(4);
		}
		else if (AIName.equals("Wander")){
			behavior = new Wander(20, 10);
		} 
		else if (AIName.equals("Attack")){
			//behavior = new Attack();
		}
		EntityLibrary.getInstance().put(name, new Merchant());
	}
	
	public void createMount(ArrayList<String> tokens){
		String name = tokens.get(0);
		String occupation = tokens.get(1);
		ArrayList<String> t2 = lineParser.parseStringOnCommaAndRemoveParen(tokens.get(2));
		MapPoint loc = new MapPoint(Integer.parseInt(t2.get(0)),Integer.parseInt(t2.get(1)));
		t2 = lineParser.parseStringOnCommaAndRemoveParen(tokens.get(3));
		MapPoint dir = new MapPoint(Integer.parseInt(t2.get(0)),Integer.parseInt(t2.get(1)));
		String legsName = tokens.get(4);
		String AIName = tokens.get(4);
		AIBehavior behavior = null;
		if (AIName.equals("StandStill")){
			behavior = new StandStill();
		}
		else if (AIName.equals("Follow")){
			//behavior = new Follow(4);
		}
		else if (AIName.equals("Wander")){
			behavior = new Wander(20, 10);
		} 
		else if (AIName.equals("Attack")){
			//behavior = new Attack();
		}
		EntityLibrary.getInstance().put(name, new Mount());
	}
	//"type;(subtype;)value;name;(modType,val);(modType,val);...
	public void createInventoryItem(String id){
		ArrayList<String> tokens = lineParser.parseStringOnSemicolon(id);
		String type = tokens.remove(0);
		
		if (type.equals("Armor")){
			createArmor(tokens);
		}
		else if (type.equals("Weapon")){
			createWeapon(tokens);
		}
		else if (type.equals("Consumable")){
			createConsumableItem(tokens);
		}
	}
	//has NO subtype
	public void createArmor(ArrayList<String> tokens){
		int value = Integer.parseInt(tokens.remove(0));
		String name = tokens.remove(0);
		StatsPersistMods mods = new StatsPersistMods();
		for (String s : tokens){
			ArrayList<String> mod = lineParser.parseStringOnCommaAndRemoveParen(s);
			addModifier(mod, mods);
		}
		ItemsLibrary.getInstance().put(name, new Armor(value, name, mods));
	}
	public void createWeapon(ArrayList<String> tokens){
		String type = tokens.remove(0);
		if (type.equals("BrawlWeapon")){
			createBrawl(tokens);
		}
		else if (type.equals("OneHandedWeapon")){
			createOneHand(tokens);
		}
		else if (type.equals("RangedWeapon")){
			createRanged(tokens);
		}
		else if (type.equals("StaffWeapon")){
			createStaff(tokens);
		}
		else if (type.equals("TwoHandedWeapon")){
			createTwoHand(tokens);
		}
	}	
	//"name;val;effectName"
	public void createConsumableItem(ArrayList<String> tokens){
		String name = tokens.get(0);
		int value = Integer.parseInt(tokens.get(1));
		Effect effect = EffectsLibrary.getInstance().getEffect(tokens.get(2));
		ItemsLibrary.getInstance().put(name, new Consummable(value, name, effect));
	}
	public void createBrawl(ArrayList<String> tokens){
		int value = Integer.parseInt(tokens.remove(0));
		String name = tokens.remove(0);
		StatsPersistMods mods = new StatsPersistMods();
		for (String s : tokens){
			ArrayList<String> mod = lineParser.parseStringOnCommaAndRemoveParen(s);
			addModifier(mod, mods);
		}
		ItemsLibrary.getInstance().put(name, new BrawlWeapon(value, name, mods));
	}
	public void createOneHand(ArrayList<String> tokens){
		int value = Integer.parseInt(tokens.remove(0));
		String name = tokens.remove(0);
		StatsPersistMods mods = new StatsPersistMods();
		for (String s : tokens){
			ArrayList<String> mod = lineParser.parseStringOnCommaAndRemoveParen(s);
			addModifier(mod, mods);
		}
		ItemsLibrary.getInstance().put(name, new OneHandedWeapon(value, name, mods));
	}
	public void createRanged(ArrayList<String> tokens){
		int value = Integer.parseInt(tokens.remove(0));
		String name = tokens.remove(0);
		StatsPersistMods mods = new StatsPersistMods();
		for (String s : tokens){
			ArrayList<String> mod = lineParser.parseStringOnCommaAndRemoveParen(s);
			addModifier(mod, mods);
		}
		ItemsLibrary.getInstance().put(name, new RangedWeapon(value, name, mods));
	}
	public void createStaff(ArrayList<String> tokens){
		int value = Integer.parseInt(tokens.remove(0));
		String name = tokens.remove(0);
		StatsPersistMods mods = new StatsPersistMods();
		for (String s : tokens){
			ArrayList<String> mod = lineParser.parseStringOnCommaAndRemoveParen(s);
			addModifier(mod, mods);
		}
		ItemsLibrary.getInstance().put(name, new StaffWeapon(value, name, mods));
	}
	public void createTwoHand(ArrayList<String> tokens){
		int value = Integer.parseInt(tokens.remove(0));
		String name = tokens.remove(0);
		StatsPersistMods mods = new StatsPersistMods();
		for (String s : tokens){
			ArrayList<String> mod = lineParser.parseStringOnCommaAndRemoveParen(s);
			addModifier(mod, mods);
		}
		ItemsLibrary.getInstance().put(name, new TwoHandedWeapon(value, name, mods));
	}
	
	//[modType,val]
	public void addModifier(ArrayList<String> mod, StatsPersistMods s){
		String modType = mod.get(0);
		int value = Integer.parseInt(mod.get(1));
		
		if(modType.equals("Strength")){
			s.addStrengthMod(value);
		}
		else if(modType.equals("Agil")){
			s.addAgilityMod(value);
		}
		else if(modType.equals("Intel")){
			s.addIntellectMod(value);
		}
		else if(modType.equals("Hard")){
			s.addHardinessMod(value);
		}
		else if(modType.equals("Mov")){
			s.addMovmentMod(value);
		}
		else if(modType.equals("MaxHealth")){
			s.addMaxHealthMod(value);
		}
		else if(modType.equals("MaxMana")){
			s.addMaxManaMod(value);
		}
		else if(modType.equals("Offense")){
			s.addOffenseMod(value);
		}
		else if(modType.equals("Defense")){
			s.addDefenseMod(value);
		}
		else if(modType.equals("Armor")){
			s.addArmorMod(value);
		}
	}
	public void addTempModifier(ArrayList<String> mod, StatsTempMods s){
		String modType = mod.get(0);
		int value = Integer.parseInt(mod.get(1));
		int duration = Integer.parseInt(mod.get(2));		
		if(modType.equals("Strength")){
			s.addStrenghtMod(value, duration);
		}
		else if(modType.equals("Agil")){
			s.addAgilityMod(value, duration);
		}
		else if(modType.equals("Intel")){
			s.addIntellectMod(value, duration);
		}
		else if(modType.equals("Hard")){
			s.addHardinessMod(value, duration);
		}
		else if(modType.equals("Mov")){
			s.addMovmentMod(value, duration);
		}
		else if(modType.equals("MaxHealth")){
			s.addMaxHealthMod(value, duration);
		}
		else if(modType.equals("MaxMana")){
			s.addMaxManaMod(value, duration);
		}
		else if(modType.equals("Offense")){
			s.addOffenseMod(value, duration);
		}
		else if(modType.equals("Defense")){
			s.addDefenseMod(value, duration);
		}
		else if(modType.equals("Armor")){
			s.addArmorMod(value, duration);
		}
	}
	

	//******ABILITIES******//
	//"TYPE: 'Interactive' or 'Map';SUBTYPE: all interactive/map abilities;&&&&&&&ct"
	public void createAbility(String id){
		ArrayList<String> tokens = lineParser.parseStringOnSemicolon(id);
		String type = tokens.remove(0);
		if (type.equals("Interactive")){
			createInteractiveAbility(tokens);
		}
		else if (type.equals("Map")){
			createMapAbility(tokens);
		}
	}
	//"subtype;abilityName;skillName;mana;delay;targetName
	public void createInteractiveAbility(ArrayList<String> tokens){
		String subtype = tokens.remove(0);
		if (subtype.equals("Observe")){
			createObserveAbility(tokens);
		}
		else if (subtype.equals("PickPocket")){
			createPickPocketAbility(tokens);
		}
		else if (subtype.equals("Sleep")){
			createSleepAbility(tokens);
		}
		else if (subtype.equals("Enchant")){
			createEnchantAbility(tokens);
		}
		else if (subtype.equals("BindWounds")){
			createBindWoundsAbility(tokens);
		}
	}
	public void createObserveAbility(ArrayList<String> tokens){
		String abilityName = tokens.get(0);
		String skillName = tokens.get(1);
		int mana = Integer.parseInt(tokens.get(2));
		int delay = Integer.parseInt(tokens.get(3));
		AbilitiesLibrary.getInstance().putInteractive(abilityName, new Observe(abilityName,SkillsLibrary.getInstance().getSkill(skillName), mana, delay));
	}
	public void createPickPocketAbility(ArrayList<String> tokens){
		String abilityName = tokens.get(0);
		String skillName = tokens.get(1);
		int mana = Integer.parseInt(tokens.get(2));
		int delay = Integer.parseInt(tokens.get(3));
		AbilitiesLibrary.getInstance().putInteractive(abilityName, new PickPocket(abilityName,SkillsLibrary.getInstance().getSkill(skillName), mana, delay));
	}
	public void createSleepAbility(ArrayList<String> tokens){
		String abilityName = tokens.get(0);
		String skillName = tokens.get(1);
		int mana = Integer.parseInt(tokens.get(2));
		int delay = Integer.parseInt(tokens.get(3));
		int duration = Integer.parseInt(tokens.get(4));
		AbilitiesLibrary.getInstance().putInteractive(abilityName, new Sleep(abilityName,SkillsLibrary.getInstance().getSkill(skillName), mana, delay, duration));
	}
	public void createEnchantAbility(ArrayList<String> tokens){
		String abilityName = tokens.get(0);
		String skillName = tokens.get(1);
		int mana = Integer.parseInt(tokens.get(2));
		int delay = Integer.parseInt(tokens.get(3));
		int duration = Integer.parseInt(tokens.get(4));
		AbilitiesLibrary.getInstance().putInteractive(abilityName, new Enchant(abilityName,SkillsLibrary.getInstance().getSkill(skillName), mana, delay, duration));
	}
	public void createBindWoundsAbility(ArrayList<String> tokens){
		String abilityName = tokens.get(0);
		String skillName = tokens.get(1);
		int mana = Integer.parseInt(tokens.get(2));
		int delay = Integer.parseInt(tokens.get(3));
		AbilitiesLibrary.getInstance().putInteractive(abilityName, new BindWounds(abilityName,SkillsLibrary.getInstance().getSkill(skillName), mana, delay));
	}
	
	public void createMapAbility(ArrayList<String> tokens){
		String subType = tokens.remove(0);
		if (subType.equals("SelfMapAbility")){
			createSelfMapAbility(tokens);
		}
		else if (subType.equals("StraightAheadAbility")){
			createStraightAheadAbility(tokens);
		}
		else if (subType.equals("RangedMapAbility")){
			createRangedMapAbility(tokens);
		}
	}
	//"abName;skName;mana;delay;efName;abType"
	public void createSelfMapAbility(ArrayList<String> tokens){
		String abilityName = tokens.get(0);
		String skillName = tokens.get(1);
		int mana = Integer.parseInt(tokens.get(2));
		int delay = Integer.parseInt(tokens.get(3));
		String effectName = tokens.get(4);
		String abilityType = tokens.get(5);
		AbilityType a = null;
		if (abilityType.equals("Caster")){
			a = new Caster();
		}
		else if (abilityType.equals("Rougue")){
			a = new Rougue();
		}
		else if (abilityType.equals("Fighter")){
			a = new Fighter();
		}
		SelfMapAbility s = new SelfMapAbility(abilityName, SkillsLibrary.getInstance().getSkill(skillName)
				, mana, delay, EffectsLibrary.getInstance().getEffect(effectName), a);
		AbilitiesLibrary.getInstance().putMap(abilityName, s);
	}
	//"abName;skName;mana;delay;efName;abType;graphicID;duration"
	public void createStraightAheadAbility(ArrayList<String> tokens){
		String abilityName = tokens.get(0);
		String skillName = tokens.get(1);
		int mana = Integer.parseInt(tokens.get(2));
		int delay = Integer.parseInt(tokens.get(3));
		String effectName = tokens.get(4);
		String abilityType = tokens.get(5);
		String graphicID = tokens.get(6);
		int duration = Integer.parseInt(tokens.get(7));
		AbilityType a = null;
		if (abilityType.equals("Caster")){
			a = new Caster();
		}
		else if (abilityType.equals("Rougue")){
			a = new Rougue();
		}
		else if (abilityType.equals("Fighter")){
			a = new Fighter();
		}
		StraightAheadAbility s = new StraightAheadAbility(abilityName, SkillsLibrary.getInstance().getSkill(skillName)
				, mana, delay, EffectsLibrary.getInstance().getEffect(effectName), a, graphicID
				, duration);
		//System.out.println("***"+abilityName);
		AbilitiesLibrary.getInstance().putMap(abilityName, s);
	}
	//"abName;skName;mana;delay;efName;abType;graphicID;algoName;duration;min;max,propogationDelay"
	public void createRangedMapAbility(ArrayList<String> tokens){
		String abilityName = tokens.get(0);
		String skillName = tokens.get(1);
		int mana = Integer.parseInt(tokens.get(2));
		int delay = Integer.parseInt(tokens.get(3));
		String effectName = tokens.get(4);
		String abilityType = tokens.get(5);
		String graphicID = tokens.get(6);
		String algoName = tokens.get(7);
		int duration = Integer.parseInt(tokens.get(8));
		int min = Integer.parseInt(tokens.get(9));
		int max = Integer.parseInt(tokens.get(10));
		int propogationDelay = Integer.parseInt(tokens.get(11));
		AbilityType a = null;
		if (abilityType.equals("Caster")){
			a = new Caster();
		}
		else if (abilityType.equals("Rougue")){
			a = new Rougue();
		}
		else if (abilityType.equals("Fighter")){
			a = new Fighter();
		}
		PlacementAlgorithm p = null;
		if (algoName.equals("Line")){
			p = new Line();
		}
		else if (algoName.equals("Cone")){
			p = new Cone();
		}
		else if (algoName.equals("Radial")){
			p = new Radial();
		}
		RangedMapAbility s = new RangedMapAbility(abilityName, SkillsLibrary.getInstance().getSkill(skillName)
				, mana, delay, EffectsLibrary.getInstance().getEffect(effectName), a, graphicID
				, p, duration, min, max, propogationDelay);
		AbilitiesLibrary.getInstance().putMap(abilityName, s);
	}
	
	//"Name;GID;effectName;period;numhits;"
	public void createMapAoE(String id){
		ArrayList<String> tokens = lineParser.parseStringOnSemicolon(id);
		String name = tokens.get(0);
		String graphID = tokens.get(1);
		String effectName = tokens.get(2);
		int period = Integer.parseInt(tokens.get(3));
		int numHits = Integer.parseInt(tokens.get(4));
		Effect eff = EffectsLibrary.getInstance().getEffect(effectName);
		MapAoEsLibrary.getInstance().put(name, new MapAreaOfEffect(name, graphID, eff, period, numHits));
	}	
	
	//"Name;GID;effectName;visibleID"
	public void createTrap(String id){
		ArrayList<String> tokens = lineParser.parseStringOnSemicolon(id);
		String name = tokens.get(0);
		String graphID = tokens.get(1);
		String effectName = tokens.get(2);
		String visGraphID = tokens.get(3);
		Effect eff = EffectsLibrary.getInstance().getEffect(effectName);
		TrapsLibrary.getInstance().put(name, new Trap(name, graphID, eff, visGraphID));
	}
}
